export class Layer {
	constructor(viewer, iCesium) {
		this.viewer = viewer;
		this.iCesium = iCesium;
		this.layerList = [];
		this.type = 'all';
		this.detail = false;
		this.types = ['Layer', 'ImageryProvider', 'VectorTilesMap', 'TerrainLayer'];
	}

	async get(type = 'all', detail = false) {
		this.type = type;
		this.detail = detail;

		const layers = this.viewer.scene.layers.layerQueue;
		let imageryLayers = this.viewer.imageryLayers._layers;
		const vectorTileMaps = this.viewer.scene._vectorTileMaps._layerQueue;
		const terrainLayers = this.viewer.scene.terrainLayers._layers;

		layers.forEach((layer) => {
			if (!layer) return;
			if (!layer.type) layer.type = 'Layer';
			if (!layer.iid) layer.iid = '0x010000' + layer.id;
		});
		imageryLayers = imageryLayers.filter((layer) => {
			if (!layer) return;
			if (!layer.type) layer.type = 'ImageryProvider';
			if (!layer.iid) layer.iid = '0x020000' + layer._imageryProvider._id;
			return !layer._imageryProvider._MVTStyle;
		});
		vectorTileMaps.forEach((layer) => {
			if (!layer) return;
			if (!layer.type) layer.type = 'VectorTilesMap';
			if (!layer.iid) layer.iid = '0x030000' + layer._id;
		});
		terrainLayers.forEach((layer, index) => {
			if (!layer) return;
			if (!layer.type) layer.type = 'TerrainLayer';
			if (!layer.iid) layer.iid = '0x040000' + index;
		});

		this.layerList = [...layers, ...imageryLayers, ...vectorTileMaps, ...terrainLayers];

		let result = this.layerList.slice();
		if (this.types.includes(type)) {
			result = result.filter((layer) => layer.type === type);
		}
		if (!detail) {
			result = result.map((layer) => {
				return {
					id: layer.iid,
					index: layer.index ?? layer._imageryProvider?._id ?? -1,
					name: layer.name ?? layer._imageryProvider?._name ?? `${layer.type}@${layer.iid}`,
					type: layer.type,
					visibility: layer.show ?? layer.visible,
					transparent: layer.alpha ?? -1
				};
			});
		}

		return result;
	}

	async show(ids) {
		const show = (layer) => {
			switch (layer.type) {
				case 'Layer':
					layer.visible = true;
					break;
				case 'ImageryProvider':
					layer.show = true;
					break;
				case 'VectorTilesMap':
					layer.show = true;
					break;
				case 'TerrainLayer':
					layer.visible = true;
					break;
				default:
					layer.show = true;
					break;
			}
		};

		const layers = this.find(ids);
		layers.forEach((layer) => show(layer));
	}

	async showAll() {
		const list = await this.get(this.type, this.detail);
		this.show(list.map((layer) => (this.detail ? layer.iid : layer.id)));
	}

	async hide(ids) {
		const hide = (layer) => {
			switch (layer.type) {
				case 'Layer':
					layer.visible = false;
					break;
				case 'ImageryProvider':
					layer.show = false;
					break;
				case 'VectorTilesMap':
					layer.show = false;
					break;
				case 'TerrainLayer':
					layer.visibility = false;
					break;
				default:
					layer.show = false;
					break;
			}
		};

		const layers = this.find(ids);
		layers.forEach((layer) => hide(layer));
	}

	async hideAll() {
		const list = await this.get(this.type, this.detail);
		this.hide(list.map((layer) => (this.detail ? layer.iid : layer.id)));
	}

	async transparent(ids, opacity = 0.6) {
		const transparent = (layer) => {
			switch (layer.type) {
				case 'Layer':
					layer.style3D.fillForeColor = new this.iCesium.Color(1.0, 1.0, 1.0, opacity);
					break;
				case 'ImageryProvider':
					layer.alpha = opacity;
					break;
				case 'VectorTilesMap':
					layer.alpha = opacity;
					break;
				case 'TerrainLayer':
					layer.alpha = opacity;
					break;
				default:
					layer.alpha = opacity;
					break;
			}
		};

		const layers = this.find(ids);
		layers.forEach((layer) => transparent(layer));
	}

	async focus(ids, distance, flyTime) {
		const options = {
			offset: distance,
			duration: flyTime
		};

		const layers = this.find(ids);
		const target = layers.filter((layer) => {
			return layer.type === 'VectorTilesMap' ? layer._provider.innerLayer : layer;
		});
		this.viewer.flyTo(target[0], options);
	}

	async remove(ids) {
		const remove = (layer) => {
			switch (layer.type) {
				case 'Layer':
					this.viewer.scene.layers.remove(layer.name);
					break;
				case 'ImageryProvider':
					this.viewer.scene.imageryLayers.remove(layer);
					break;
				case 'VectorTilesMap':
					this.viewer.scene.removeVectorTilesMap.remove(layer);
					break;
				case 'TerrainLayer':
					this.viewer.scene.terrainLayers.remove(layer);
					break;
				default:
					break;
			}
		};

		const layers = this.find(ids);
		layers.forEach((layer) => remove(layer));
	}

	find(ids) {
		ids = Array.isArray(ids) ? ids : [ids];
		const result = ids.map((id) => this.layerList.filter((item) => item.iid === id));
		return result.flat();
	}
}
